home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Personal Computer World 2009 February
/
PCWFEB09.iso
/
Software
/
Resources
/
Chat & Communication
/
PeerAware 1.03
/
PeerAware-Setup.exe
/
Html
/
scripts
/
richdraw.js
< prev
next >
Wrap
Text File
|
2008-09-07
|
68KB
|
2,302 lines
/* ***** BEGIN LICENSE BLOCK *****
This code has been relicensed under LGPL as permitted by original license.
Copyright Cumulate Draw Editor
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
* ***** END LICENSE BLOCK ***** */
/**
*RichDrawEditor: the idea is to provide an abstract editor interface which
*manipulates vml or svg renderers,
*
*constructor, set up initial values for state variables and add listeners
**/
function RichDrawEditor(elem, renderer) {
gApplication = new Application();
this.initialized=false;
this.iUser='';
this.container = elem;
this.page=$("_page");
this.width=700;
this.height=700;
this.DEFAULT_PAGE_WIDTH=700;
this.DEFAULT_PAGE_HEIGHT=700;
this.MAX_WIDTH=2000;
this.MAX_HEIGHT=2000;
this.gridX = 1;
this.gridY = 1;
this.mouseDownX = 0;
this.mouseDownY = 0;
this.prevZoom=1.0;
this.zoom=1.0;
this.prevWidth=0;
this.prevHeight=0;
this.prevLeft=0;
this.prevTop=0;
this.prevRotation=0;
this.prevMode='';
this.mode = 'select';
this.resizeMode='';//possible values are left-stretch, right-stretch,top-stretch,bottom-stretch
this.fillColor = '';
this.lineColor = '';
this.lineWidth = '';
this.lineStyle='none';
this.opacity='1.0';
this.gradient='solid';
this.linedashstyle='solid';
this.shadowOn="false";
this.shiftMode=false;
this.selected = null;
//the current shape which is under line draw!!!
this.lineActiveShape=null;
this.dragStarted=false;
this.textEditMode=false;
this.textToolBeginNew=true;
this.resizeCounter=0;
this.dragCounter=0;
var font=new Object();
font.size='';
font.family='';
font.color='';
font.align='';
font.italics='';
font.bold='';
this.fillUpFont(font);
this.font=font;
this.shapeProps=new Array();
this.shapeProps["table"]=$("_shapeTable");
this.shapeProps["x"]=$("_x");
this.shapeProps["y"]=$("_y");
this.shapeProps["width"]=$("_width");
this.shapeProps["height"]=$("_height");
this.shapeProps["rotation"]=$("_rotation");
this.lineProps=new Array();
this.lineProps["table"]=$("_connectorTable");
this.lineProps["x1"]=$("_x1");
this.lineProps["x2"]=$("_x2");
this.lineProps["y1"]=$("_y1");
this.lineProps["y2"]=$("_y2");
this.lineProps["type"]=$("_lineType");
this.pageProps=new Array();
this.pageProps["table"]=$("_pageTable");
this.pageProps["x"]=$("_pageX");
this.pageProps["y"]=$("_pageY");
this.pageProps["width"]=$("_pageWidth");
this.pageProps["height"]=$("_pageHeight");
//one day we will allow multiple objects in the clipboard
this.clipboard=null;
this.selectedBounds = { x:0, y:0, width:0, height: 0 };
this.onselect = function() {}
this.onunselect = function() {}
//initialize the renderer
this.renderer = renderer;
this.renderer.init(this.container);
this.onMouseDownListener = this.onMouseDown.bindAsEventListener(this);
this.onMouseUpListener = this.onMouseUp.bindAsEventListener(this);
this.onDragListener = this.onDrag.bindAsEventListener(this);
this.onDrawListener = this.onDraw.bindAsEventListener(this);
this.onHitListener = this.onHit.bindAsEventListener(this);
this.onSelectStartListener = this.onSelectStart.bindAsEventListener(this);
this.onMouseOverListener=this.onMouseOver.bindAsEventListener(this);
this.onMouseOutListener=this.onMouseOut.bindAsEventListener(this);
this.onShapeMouseOutListener=this.onShapeMouseOut.bindAsEventListener(this);
this.onShapeMouseEnterListener=this.onShapeMouseEnter.bindAsEventListener(this);
this.onKeyPressListener=this.onKeyPress.bindAsEventListener(this);
this.onKeyUpListener=this.onKeyUp.bindAsEventListener(this);
this.onDblClickListener=this.onDblClick.bindAsEventListener(this);
this.onTextEditEndListener=this.onTextEditEnd.bindAsEventListener(this);
Event.observe(this.container, "mousedown", this.onMouseDownListener);
Event.observe(this.container, "mouseup", this.onMouseUpListener);
Event.observe(this.container,"mouseout",this.onMouseOutListener);
Event.observe(this.container, "selectstart", this.onSelectStartListener);
Event.observe(this.container.ownerDocument,'keypress',this.onKeyPressListener);
Event.observe(this.container.ownerDocument,'keyup',this.onKeyUpListener);
}
/**
*setup initial values for the font
**/
RichDrawEditor.prototype.fillUpFont=function(font){
if(font.size=='')
font.size=16;
if(font.family=='')
font.family="'arial'";
if(font.italics=='')
font.italics="normal";
if(font.bold=='')
font.bold="normal"
if(font.align=='')
font.align="center";
if(font.color=='')
font.color="black";
}
/**
*Initialized the workspace
**/
RichDrawEditor.prototype.initializationDone = function() {
this.initialized=true;
};
/**
*clear the workspace
**/
RichDrawEditor.prototype.clearWorkspace = function() {
this.container.innerHTML = '';
};
/******************************begin cut/copy/paste/delete operations***********************************/
/**
*delete the selection and remove the trackers
**/
RichDrawEditor.prototype.deleteSelection = function() {
if (this.selected) {
//remove all tracker components!!
if($('tracker-group')){
Event.stopObserving($('tracker-group'),"mouseover",this.onMouseOverListener);
}
Event.stopObserving(this.selected,"dblclick",this.onDblClickListener);
this.renderer.remove(this.container.ownerDocument.getElementById('tracker-group'));
this.renderer.remove(this.selected);
this.selected = null;
//this.updateShapeInfo(null);
}
else{
setHelp("Select a shape to delete");
}
};
/**
*copy and then delete the selection
**/
RichDrawEditor.prototype.cut=function(){
if(this.selected){
this.copy();
this.deleteSelection();
this.unselect();
}
else{
setHelp("Nothing to cut,Please select a shape first");
}
};
/**
*Save to the clipboard
*/
RichDrawEditor.prototype.copyToRemote=function(){
if(this.selected){
return this.renderer.copy(this.selected);
}
return null;
};
RichDrawEditor.prototype.copy=function(){
if(this.selected){
//I know this is weird but clone node does not seem to work,so we copy the outer html
this.clipboard=this.renderer.copy(this.selected);
}
else{
setHelp("Nothing to copy,Please select a shape first");
}
};
/**
*paste function
*wierd IE bug which forces us to set zindex of lines to 0 until they are added
*nodeArray[i].getElementsByTagName("line")[0].style.zIndex=0;
*another wierdness is that polyline.points.value does not correspond to polyline.points.item(x).value, so we
* first set the points to 0,0, then add them to the container and then set the orignal points which we preserved
* during copy, where we called savePolyLinePath
**/
RichDrawEditor.prototype.paste=function(){
if(this.clipboard!=null){
var node=this.renderer.paste(this.clipboard);
//add listener to added child
this.addNewShapeListeners(node);
this.clipboard=this.renderer.copy(node);
return node;
}
else{
setHelp("Nothing to paste,Use copy or cut on selected shape");
}
}
/**
* a utility function to add all the required listener after a new shape has been
* added
**/
RichDrawEditor.prototype.addNewShapeListeners=function(shape){
if(!shape)return;
Event.observe(shape, "mousedown", this.onHitListener);
Event.observe(shape,"mouseover",this.onShapeMouseEnterListener);
Event.observe(shape,"mouseout",this.onShapeMouseOutListener);
}
/****END DELETE, CUT,COPY,PASTE functions*****************/
/****************BRING TO FRONT/BACK FUNCTIONS*************************/
/**
*bring to front,the listeners are refreshed since in SVG there is no real z-index operation, so
*we remove and readd!
*@param shape
**/
RichDrawEditor.prototype.bringToFront=function(shape){
var subject=(shape)?shape:this.selected;
subject=this.renderer.bringToFront(subject);
if(subject){
this.addNewShapeListeners(subject);
this.select(subject);
}
}
/**
*send to back, the listeners are refreshed since in SVG there is no real z-index operation, so
*we remove and readd!.
*@param shape
**/
RichDrawEditor.prototype.sendToBack=function(shape){
var subject=(shape)?shape:this.selected;
var subject=this.renderer.sendToBack(subject);
if(subject){
this.addNewShapeListeners(subject);
this.select(subject);
}
}
/*********************END BRING TO FRONT/BACK FUNCTIONS**********************/
/**
* select and show tracker
**/
RichDrawEditor.prototype.select = function(elem) {
if (elem == this.selected)
return;
this.selected = elem;
var tracker=this.renderer.showTracker(this.selected);
Event.observe(tracker,"mouseover",this.onMouseOverListener);
// if(!this.renderer.isConnector(this.selected)){
Event.observe(this.selected,"dblclick",this.onDblClickListener);
//}
setHelp("To move the shape, drag it. To resize, use resize boxes.<b>To Set Text, double click</b>");
this.onselect(this);
this.updateShapeInfo(this.selected);
};
/**
*unselect and remove tracker,
*if text is being edited, end that operation.
**/
RichDrawEditor.prototype.unselect = function() {
if (this.selected!=null) {
if(this.textEditMode){
this.finishTextEdit();
this.textEditMode=false;
}
if(this.mode!="text"){
this.textModeBeginNew=false;
}
Event.stopObserving(this.selected,"dblclick",this.onDblClickListener);
this.selected = null;
this.onunselect(this);
Event.stopObserving(this.container,"mouseover",this.onMouseOverListener);
this.updateShapeInfo(null);
if(this.container.ownerDocument.getElementById('tracker-group')!=null){
this.renderer.remove(this.container.ownerDocument.getElementById('tracker-group'));
}
var activeShapeTracker=$("active-shape-tracker");
if(activeShapeTracker)
this.renderer.remove(activeShapeTracker);
}
var lineTracker=$("line-tracker");
if(lineTracker){
this.renderer.remove(lineTracker);
}
}
/***************************************TEXT related functions************************/
/**
*this is called when a shape is double clicked,
*it displays the text box for the selected shape
**/
RichDrawEditor.prototype.onDblClick=function(event){
if(!this.selected){
return false;
}
else{
this.startTextEdit(this.selected);
}
}
/**
*start the text editing
*@param {shape} the shape
**/
RichDrawEditor.prototype.startTextEdit=function(shape){
setHelp("Enter your text and then click anywhere outside the text area");
var text=$('__shapeText');
var textString=this.renderer.getShapeText(shape);
if(textString){
text.value=textString;
}
else{
text.value="";
}
text.style.visibility="visible";
var bounds=this.renderer.getTextBounds(shape,"",this.zoom);
text.style.marginLeft=bounds.x>3?(bounds.x-3):0;
text.style.marginTop=bounds.y>3?(bounds.y-3):0;
if(bounds.width>=35){
text.style.width=parseInt(bounds.width)+6;
}
else{
text.style.width=35;
}
if(bounds.height>=35){
text.style.height=parseInt(bounds.height)+6;
}
else{
text.style.height=35;
}
this.setTextAreaFont(text);
this.renderer.remove(text);
this.container.appendChild(text);
text.focus();
text.style.zIndex=this.renderer.maxIndex;
Event.stopObserving(this.container, "mousedown", this.onMouseDownListener);
Event.stopObserving(this.container, "mouseup", this.onMouseUpListener);
Event.stopObserving(this.container, "selectstart", this.onSelectStartListener);
Event.stopObserving(this.container,'keypress',this.onKeyPressListener);
Event.stopObserving(this.container,'keyup',this.onKeyUpListener);
Event.stopObserving(this.container, "mousemove", this.onDragListener);
Event.observe(this.container,'mousedown',this.onTextEditEndListener);
setTimeout("c.manageTextSize()",100);
this.textEditMode=true;
}
/**
* manage the size of the text area based on size of the text being entered
*/
RichDrawEditor.prototype.manageTextSize=function(){
if(!this.selected||(!this.renderer.isConnector(this.selected)&&(!this.selected.getElementsByTagName("text-bound")>0)))return;
var text=$('__shapeText');
if(!text.style.visibility=="visible")return;
var bounds=this.renderer.getTextBounds(this.selected,text.value,this.zoom);
text.style.marginLeft=bounds.x>3?(bounds.x-3):0;
text.style.marginTop=bounds.y>3?(bounds.y-3):0;
if(bounds.width>=35){
text.style.width=parseInt(bounds.width)+6;
}
else{
text.style.width=35;
}
if(bounds.height>=35){
text.style.height=parseInt(bounds.height)+6;
}
else{
text.style.height=35;
}
setTimeout("c.manageTextSize()",100);
}
/**
*basically set the font of the test area based on either
*the currently selected shape's font properties or the default
*if the current shape is empty
**/
RichDrawEditor.prototype.setTextAreaFont=function(text){
var shapeFont=this.renderer.getFont(this.selected);
if(shapeFont.size!=''){
text.style.fontSize=(shapeFont.size*this.zoom);
}
else{
text.style.fontSize=(this.font.size*this.zoom);
}
if(shapeFont.color!=''){
text.style.strokecolor=shapeFont.color;
text.style.color=shapeFont.color;
}
else{
text.style.strokecolor=this.font.color;
text.style.color=this.font.color;
}
if(shapeFont.family!=''){
text.style.fontFamily=shapeFont.family;
}
else{
text.style.fontFamily=this.font.family;
}
if(shapeFont.bold!=''){
text.style.fontWeight=shapeFont.bold;
}
else{
text.style.fontWeight=this.font.bold;
}
if(shapeFont.italics!=''){
text.style.fontStyle=shapeFont.italics;
}
else{
text.style.fontStyle=this.font.italics;
}
}
/**
*called when user clicks an area other than the active text area,
*signals end of text editing, time to set the text in the shape
**/
RichDrawEditor.prototype.onTextEditEnd=function(event){
if(!this.selected||!this.textEditMode||!event){
return;
}
else{
var source=Event.element(event);
if(event&&source&&source.id=="__shapeText"){
return;
}
this.finishTextEdit();
this.unselect();
}
};
/**
*this method should be called when we want to force the text edit operation to end
**/
RichDrawEditor.prototype.finishTextEdit=function(){
setHelp("Finished editing text");
var shapeText=$('__shapeText');
var text=shapeText.value;
if(!text||text.length==0)text=" ";
this.clearShapeText();
var shapeFont=this.renderer.getFont(this.selected);
this.renderer.setShapeText(this.selected,text,this.font,false,shapeFont,this.zoom);
if(this.mode=="text"&&!this.textToolBeginNew)
{
var transmitData = this.copyToRemote();
if (transmitData != null)
gApplication.transmit('w', "cpy " + transmitData);
}
else
gApplication.transmit('w', 'cmd txt txt ' + this.selected.id + ' ' + text);
if(!this.renderer.isConnector(this.selected)){
this.resetTextForAttachedConnectors(this.selected);
}
shapeText.style.visibility="hidden";
this.textEditMode=false;
Event.observe(this.container, "mousedown", this.onMouseDownListener);
Event.observe(this.container, "mouseup", this.onMouseUpListener);
Event.observe(this.container, "selectstart", this.onSelectStartListener);
Event.observe(this.container,'keypress',this.onKeyPressListener);
Event.observe(this.container,'keyup',this.onKeyUpListener);
Event.stopObserving(this.container,"mousedown",this.onTextEditEndListener);
}
/**
*clear the shape text, this removes the shape text and stores it in a temporary location, we do this for performance
* reasons, since we don't want to draw every single shape line every time we move.
* @param shape--optional, if no shape provided, this.selected will be used
**/
RichDrawEditor.prototype.clearShapeText=function(shape){
var subject=shape;
if(!subject){
subject=this.selected;
}
if(subject){
this.renderer.getShapeText(subject);
this.renderer.getFont(subject);
this.renderer.clearShapeText(subject);
if(!this.renderer.isConnector(subject)){
this.clearTextForAttachedConnectors(subject);
}
}
}
/**
*reset the shape text after the shape move is complete
*@param shape--optional, if no shape provided, this.selected will be used
*/
RichDrawEditor.prototype.resetShapeText=function(shape){
var subject=shape;
if(!subject){
subject=this.selected;
}
if(subject){
var text=this.renderer.getShapeText(subject);
var shapeFont=this.renderer.getFont(subject);
if(text){
this.renderer.setShapeText(subject,text,this.font,false,shapeFont,this.zoom);
}
if(!this.renderer.isConnector(subject)){
this.resetTextForAttachedConnectors(subject);
}
}
}
/**
* clear the text for all the connectors attached to a particular shape
* @param shape--optional, if no shape provided, this.selected will be used
*/
RichDrawEditor.prototype.clearTextForAttachedConnectors=function(shape){
var subject=shape;
if(!subject)
subject=this.selected;
var connList=this.renderer.getAllConnectorsForShape(subject);
for(var i=0;i<connList.length;i++){
if(connList[i]){
this.clearShapeText(connList[i]);
}
}
}
/**
* reset the text for all the connectors attached to a particular shape
* @param shape--optional, if no shape provided, this.selected will be used
*/
RichDrawEditor.prototype.resetTextForAttachedConnectors=function(shape){
var subject=shape;
if(!subject)
subject=this.selected;
var connList=this.renderer.getAllConnectorsForShape(shape);
for(var i=0;i<connList.length;i++){
if(connList[i]){
this.resetShapeText(connList[i]);
}
}
}
/****************************END TEXT functions************************************/
/**
*getSeletedElement
**/
RichDrawEditor.prototype.getSelectedElement = function() {
return this.selected;
};
/**
*set grid
**/
RichDrawEditor.prototype.setGrid = function(horizontal, vertical) {
this.gridX = horizontal;
this.gridY = vertical;
};
/**
*during open, we first reset zoom to 1, add the shapes and then set it back to "zoom-factor"
*
**/
RichDrawEditor.prototype.open=function(div){
this.removeAll();
//reset the zoom to 1
this.setZoom((1.0/this.zoom));
//now call the renderer specific operations for open
this.renderer.open(div);
//get all shapes
var nodes=this.renderer.getAllShapes(this.container.ownerDocument);
var nodeArray=$A(nodes);
//get all connectors
nodes=this.renderer.getAllConnectors(this.container.ownerDocument);
for(var i=0;i<nodes.length;i++){
nodeArray[nodeArray.length]=nodes[i];
}
for(var i=0;i<nodeArray.length;i++){
var node=nodeArray[i];
this.addNewShapeListeners(node);
}
//first set the pageSize as derived from the file being opened
var pageSize=div.getElementsByTagName("page-size");
var width=this.DEFAULT_PAGE_WIDTH;
var hieght=this.DEFAULT_PAGE_HEIGHT;
if(pageSize&&pageSize.length>0){
width=pageSize.item(0).getAttribute("width");
hieght=pageSize.item(0).getAttribute("height");
}
this.setPageSize(width,hieght);
//now set the zoom
var zoomElement=div.getElementsByTagName("zoom-factor");
var factor=0.8;
if(zoomElement&&zoomElement.length>0){
factor=zoomElement.item(0).getAttribute("factor");
}
this.setZoom(factor);
$('_zoomValue').innerHTML=(this.getZoom()*100).toFixed(0)+"%";
};
/**
*used by new function to reset the editor to defaults in prepration for new
*/
RichDrawEditor.prototype.reset=function(){
gApplication.transmit('w', 'cmd reset');
this.removeAll();
this.setPageSize(this.DEFAULT_PAGE_WIDTH,this.DEFAULT_PAGE_HEIGHT);
}
/**
*used by "new" toolbar function, clear the canvas
**/
RichDrawEditor.prototype.removeAll=function(){
this.unselect();
var nodes=this.renderer.getAllShapes(this.container.ownerDocument);
var nodeArray=$A(nodes);
nodes=this.renderer.getAllConnectors(this.container.ownerDocument);
for(var i=0;i<nodes.length;i++){
nodeArray[nodeArray.length]=nodes[i];
}
for(var i=0;i<nodeArray.length;i++){
var node=nodeArray[i];
this.renderer.remove(node);
}
}
/**
*set the current edit mode
**/
RichDrawEditor.prototype.setMode=function (value){
this.mode=value;
if(value=='line'){
this.renderer.setCursor(this.container,"./cursors/line-draw.cur");
}
else if(value=='ortho-line'){
this.renderer.setCursor(this.container,"./cursors/orth-draw.cur");
}
else if(value=='curve-line'){
this.renderer.setCursor(this.container,"./cursors/curve-draw.cur");
}
else if (value=='text'){
this.renderer.setCursor(this.container,"./cursors/text.cur");
}
else{
this.renderer.setCursor(this.container,"default");
}
}
/**
*this is the driver for all toolbar related commands,
*if a shape is selected the command is delegated to the renderer
*otherwise it is handled by the editor itself
**/
RichDrawEditor.prototype.editCommand = function(cmd, value)
{
this.externaleditCommand(cmd, value, false);
}
RichDrawEditor.prototype.externaleditCommand = function(cmd, value, external)
{
if (!external && this.initialized)
{
if (!this.selected)
gApplication.transmit('w', 'cmd ' + cmd + " " + value);
else
gApplication.transmit('w', 'cmd ' + cmd + " " + value + " " + this.selected.id);
}
//debugger;
if (cmd == 'mode') {
this.setMode(value);
}
if(cmd=='zoom'){
this.setZoom(value);
}
else if (this.selected == null) {
if (cmd == 'fillcolor') {
this.fillColor = value;
}
else if (cmd == 'linecolor') {
this.lineColor = value;
}
else if (cmd == 'linewidth') {
this.lineWidth = parseInt(value) + 'px';
}
else if (cmd=='opacity'){
this.opacity=value;
}
else if (cmd=='gradient'){
this.gradient=value;
}
else if (cmd=='shadow'){
this.shadowOn=value;
}
else if(cmd=='linestyle'){
this.lineStyle=value;
}
else if(cmd=='fontSize'){
this.font.size=value;
}
else if(cmd=='fontFamily'){
this.font.family=value;
}
else if(cmd=='bold'){
if(this.font.bold=='bold'){
this.font.bold='normal';
}
else{
this.font.bold='bold';
}
}
else if(cmd=='italic'){
if(this.font.italics=='italic'){
this.font.italics='normal';
}
else{
this.font.italics='italic';
}
}
else if(cmd=='fontColor'){
this.font.color=value;
}
else if(cmd=='align'){
this.font.align=value;
}
}
else {
this.renderer.editCommand(this.selected, cmd, value,this.zoom);
if(this.textEditMode==true){
if(cmd=='fontColor'||cmd=='align'||cmd=='italic'||cmd=='bold'||cmd=='fontFamily'||cmd=='fontSize')
this.setTextAreaFont($('__shapeText'));
}
}
}
/**
* set the page width and heigh and zoom it according to current zoom factor
**/
RichDrawEditor.prototype.setPageSize=function(width,height){
if(width>this.MAX_WIDTH){
setHelp("<font color='red'>Maximum width allowed is:"+this.MAX_WIDTH+"</font>");
}
else if(height>this.MAX_HEIGHT){
setHelp("<font color='red'>Maximum height allowed is:"+this.MAX_HEIGHT+"</font>");
}
else{
this.width=width;
this.height=height;
this.page.style.width=(this.width*this.zoom)+'px';
this.page.style.height=(this.height*this.zoom)+'px';
}
this.updateShapeInfo(null);
}
/**
*get the page size and width return as an array with elements "width", "height"
**/
RichDrawEditor.prototype.getPageSize=function(){
var size=new Array();
size['width']=this.width;
size['height']=this.height;
return size;
}
/**zoom functions**/
/**
*set zoom: first set the zoom for the container, then call setShapeZoom for shapes
**/
RichDrawEditor.prototype.setZoom=function(value){
value=(this.zoom*value).toFixed(2);
if(value<0.15||value>4.0)return;
this.prevZoom=this.zoom;
this.zoom=value;
var width=this.page.style.width.split('px')[0];
var height=this.page.style.height.split('px')[0];
width=Math.round(width*(value/this.prevZoom));
height=Math.round(height*(value/this.prevZoom));
this.page.style.width=width+'px';
this.page.style.height=height+'px';
this.setShapeZoom(this.container,value,this.prevZoom);
}
/**
*set the zoom on all individual shapes, call setLineZoom for lines
**/
RichDrawEditor.prototype.setShapeZoom=function(doc,value,prevZoom){
this.renderer.remove($('tracker-group'));
this.renderer.remove($('active-shape-tracker'));
var nodes=this.renderer.getAllShapes(doc);
var length=nodes.length;
for(var i=0;i<nodes.length;i++){
var shape=nodes[i];
var rect=this.renderer.bounds(shape);
this.renderer.setWidth(shape,Math.round(parseFloat(rect['width'])*(value/prevZoom)));
this.renderer.setHeight(shape,Math.round(parseFloat(rect['height'])*(value/prevZoom)));
this.renderer.setY(shape,Math.round(parseFloat(rect['y'])*(value/prevZoom)));
this.renderer.setX(shape,Math.round(parseFloat(rect['x'])*(value/prevZoom)));
this.renderer.updateRotation(shape);
var text=this.renderer.getShapeText(shape,doc);
var font=this.renderer.getFont(shape);
this.renderer.clearShapeText(shape);
if(text)
this.renderer.setShapeText(shape,text,this.font,false,font,value);
}
this.setLineZoom(doc,value,prevZoom);
this.renderer.updateTracker(this.selected);
}
/**
*now set the zoom on all lines
**/
RichDrawEditor.prototype.setLineZoom=function(doc,value,prevZoom){
var nodes=this.renderer.getAllConnectors(doc);
var length=nodes.length;
for(var i=0;i<nodes.length;i++){
var shape=nodes[i];
var fromX=this.renderer.getConnectorFromX(shape) * (value/prevZoom);
var fromY=this.renderer.getConnectorFromY(shape) * (value/prevZoom);
var toX=this.renderer.getConnectorToX(shape) *(value/prevZoom);
var toY=this.renderer.getConnectorToY(shape)*(value/prevZoom);
this.renderer.moveLinePoint(shape,fromX,fromY,true);
this.renderer.moveLinePoint(shape,toX,toY,false);
//now get the control points if any
if(this.renderer.getConnectorType(shape)=='curve-line'){
var control1=this.renderer.getControl1(shape);
var cx1=control1.x* (value/prevZoom);
var cy1=control1.y*(value/prevZoom);
this.renderer.setControl1(shape,cx1,cy1);
var control2=this.renderer.getControl2(shape);
var cx2=control2.x* (value/prevZoom);
var cy2=control2.y*(value/prevZoom);
this.renderer.setControl2(shape,cx2,cy2);
}
var text=this.renderer.getShapeText(shape,doc);
var font=this.renderer.getFont(shape);
this.renderer.clearShapeText(shape);
if(text)
this.renderer.setShapeText(shape,text,this.font,false,font,value,doc);
}
}
/**
*get zoom factor
**/
RichDrawEditor.prototype.getZoom=function(){
return this.zoom;
}
/**
*return the current value for various commands e.g current fill value, opacity etc. If the shape is selected, the command is delegated
*to the renderer, otherwise handled by the editor
**/
RichDrawEditor.prototype.queryCommand = function(cmd)
{
if (cmd == 'mode') {
return this.mode;
}
else if (this.selected == null) {
if (cmd == 'fillcolor') {
return this.fillColor;
}
else if (cmd == 'linecolor') {
return this.lineColor;
}
else if (cmd == 'linewidth') {
return this.lineWidth;
}
else if(cmd=='opacity'){
return this.opacity;
}
else if(cmd=='gradient'){
return this.gradient;
}
else if(cmd=='shadow'){
return this.shadowOn;
}
else if(cmd=='fontSize'){
return this.font.size;
}
else if(cmd=='fontFamily'){
return this.font.family;
}
else if(cmd=='bold'){
return this.font.bold;
}
else if(cmd=='italics'){
return this.font.italics;
}
else if(cmd=='fontColor'){
return this.font.color;
}
else if(cmd=='align'){
return this.font.align;
}
else if(cmd=='font'){
return this.font;
}
else if(cmd=='linedashstyle'){
return this.linedashstyle;
}
else if(cmd=='linestyle'){
return this.lineStyle;
}
}
else {
return this.renderer.queryCommand(this.selected, cmd);
}
}
RichDrawEditor.prototype.onSelectStart = function(event) {
return false;
}
/**
* for efficieny purposes we do not redraw the text everytime a shape is moved,
*which means that when the move related keys are released,
* we need to reset shape text
**/
RichDrawEditor.prototype.onKeyUp=function(event){
var code=event.keyCode;
if((code==46||code==37||code==38||code==39||code==40)&&this.textEditMode==true)
return true;
if(code==37||code==38||code==39||code==40||code==82||code==76){
this.clearShapeText();
this.resetShapeText();
}
}
/**
*handle various key events
**/
RichDrawEditor.prototype.onKeyPress=function(event){
var code=event.keyCode;
var stop=false;
var unicode=event.charCode?event.charCode:event.keyCode;
var actualKey=String.fromCharCode(unicode);
actualKey=actualKey.toLowerCase();
if((code==46||code==37||code==38||code==39||code==40)&&this.textEditMode==true)
return;
if (gTextEditMode)
return;
if(46==code&&!this.textEditMode){
if (this.selected)
gApplication.transmit('w', 'cmd deleteSelection ' + this.selected.id);
this.deleteSelection();
stop=true;
}
//disable fine moves as this will probably generate a lot of traffic for large workspaces.
/*else if(37==code&&!this.textEditMode){
this.clearShapeText();
this.fineMove(1,0,0,0);
stop=true;
}
else if(38==code&&!this.textEditMode){
this.clearShapeText();
this.fineMove(0,0,1,0);
stop=true;
}
else if(39==code&&!this.textEditMode){
this.clearShapeText();
this.fineMove(0,1,0,0);
stop=true;
}
else if(40==code&&!this.textEditMode){
this.clearShapeText();
this.fineMove(0,0,0,1);
stop=true;
}
else if('r'==actualKey){
if(event.shiftKey&&!this.textEditMode){
this.clearShapeText();
this.fineRotateSelection(1);
stop=true;
}
}
else if('l'==actualKey){
if(event.shiftKey&&!this.textEditMode){
this.clearShapeText();
this.fineRotateSelection(-1);
stop=true;
}
}*/
else if('x'==actualKey){
if(event.ctrlKey&&!this.textEditMode)
{ this.cut();
if (this.selected)
gApplication.transmit('w', 'cmd deleteSelection ' + this.selected.id);
}
stop=true;
}
else if('c'==actualKey){
if(event.ctrlKey&&!this.textEditMode)
this.copy();
stop=true;
}
else if('v'==actualKey){
if(event.ctrlKey&&!this.textEditMode)
this.paste();;
stop=true;
}
else if('b'==actualKey){
if(event.ctrlKey){
this.editCommand("bold");
stop=true;
}
}
else if('i'==actualKey){
if(event.ctrlKey){
this.editCommand("italic");
stop=true;
}
}
else{
stop=false;
}
if(stop&&!this.textEditMode){
Event.stop(event);
return false;
}
else{
return true;
}
}
/*******************MOUSE OVER***************************/
/**
*if the mouse is over the tracker set the appropriate cursor.
*This method needs some serious cleaning up,
*there is nothing wrong with it except that the logic could be performed much more elegantly.
**/
RichDrawEditor.prototype.onMouseOver=function(event){
var source=Event.element(event);
if(source.id=='resize-bottom'||source.id=='resize-right'||source.id=="tracker-rotate"||
source.id=='resize-left'||source.id=='resize-top'){
var offset = Position.cumulativeOffset(this.container);
var snappedX = (Event.pointerX(event) - offset[0]) / this.gridX * this.gridX;
var snappedY = (Event.pointerY(event) - offset[1]) / this.gridY * this.gridY;
var rotation=this.renderer.bounds(this.selected)['rotation'];
rotation=rotation%360;
if(source.id=='resize-bottom'){
source.style.cursor='s-resize';
if(rotation!=null&&((rotation>=45&&rotation<=135)||(rotation>=225&&rotation<=315))){
source.style.cursor='e-resize';
}
else{
source.style.cursor='s-resize';
}
}
else if(source.id=='resize-top'){
source.style.cursor='s-resize';
if(rotation!=null&&((rotation>=45&&rotation<=135)||(rotation>=225&&rotation<=315))){
source.style.cursor='e-resize';
}
else{
source.style.cursor='s-resize';
}
}
else if(source.id=='resize-right'){
source.style.cursor='e-resize';
if(rotation!=null&&((rotation>=45&&rotation<=135)||(rotation>=225&&rotation<=315))){
source.style.cursor='s-resize';
}
else{
source.style.cursor='e-resize';
}
}
else if(source.id=='resize-left'){
source.style.cursor='e-resize';
if(rotation!=null&&((rotation>=45&&rotation<=135)||(rotation>=225&&rotation<=315))){
source.style.cursor='s-resize';
}
else{
source.style.cursor='e-resize';
}
}
else if(source.id=="tracker-rotate"){
source.style.cursor='move';
this.resizeMode="rotate";
}
}
return false;
}
/*******************MOUSE DOWN***************************/
/**
*handle mouse down related events, another refactoring candidate, too much going on in here...
**/
RichDrawEditor.prototype.onMouseDown = function(event) {
var offset = Position.cumulativeOffset(this.container);
var snappedX = Math.round((Event.pointerX(event) - offset[0]) / this.gridX) * this.gridX;
var snappedY = Math.round((Event.pointerY(event) - offset[1]) / this.gridY) * this.gridY;
var source=Event.element(event);
if(source.id=='resize-bottom'||source.id=='resize-right'||source.id=="tracker-rotate"||
source.id=='resize-left'||source.id=='resize-top'||source.id=='resize-from'||source.id=='resize-to'
||source.id=='control1'||source.id=='control2'){
this.prevMode=this.mode;
this.setMode('resize');
if(this.selected){
this.mouseDownX = snappedX;
this.mouseDownY = snappedY;
var rect=this.renderer.bounds(this.selected);
this.prevWidth=rect['width'];
this.prevLeft=rect['x'];
this.prevHeight=rect['height'];
this.prevTop=rect['y'];
this.prevRotation=rect['rotation'];
if(!this.prevRotation)
this.prevRotation=0;
if(source&&source.id){
if(source.id=='resize-from'){
this.resizeMode='line-from';
}
else if(source.id=='resize-to'){
this.resizeMode='line-to';
}
else if(source.id=='control1'){
this.resizeMode='control1';
}
else if(source.id=='control2'){
this.resizeMode='control2';
}
else if(source.id=='resize-bottom'){
this.resizeMode="bottom-stretch";
}
else if(source.id=='resize-top'){
this.resizeMode="top-stretch";
}
else if(source.id=='resize-right'){
this.resizeMode="right-stretch";
}
else if(source.id=='resize-left'){
this.resizeMode="left-stretch";
}
else if(source.id=="tracker-rotate"){
this.resizeMode="rotate";
}
this.clearShapeText();
}
}
// if(this.resizeMode=="rotate"){
// setHelp("For Fine rotation use <B>Shift+R</B> and <B>Shift+L</B>");
// }
Event.observe(this.container, "mousemove", this.onDrawListener);
}
else if (this.mode != 'select'&&this.mode!='resize') {
this.unselect();
setHelp("Drag your mouse to size the selected shape");
this.mouseDownX = snappedX;
this.mouseDownY = snappedY;
if(this.mode!='line'&&this.mode!='ortho-line'&&this.mode!='curve-line'){
var mouseX=(this.mouseDownX*1)+this.container.parentNode.scrollLeft;
var mouseY=( this.mouseDownY*1)+this.container.parentNode.scrollTop;
this.selected = this.renderer.create(this.mode, this.fillColor, this.lineColor, this.lineWidth, mouseX, mouseY, 1, 1,this.opacity,this.gradient,this.shadowOn);
this.selected.setAttribute('id', 'shape:' + createUUID());
this.addNewShapeListeners(this.selected);
if(this.mode=="text"){
this.textToolBeginNew=true;
}
}
else{
var mouseX=(this.mouseDownX*1)+this.container.parentNode.scrollLeft;
var mouseY=( this.mouseDownY*1)+this.container.parentNode.scrollTop;
this.unselect();
this.selected = this.renderer.createLine(this.mode, this.lineColor, this.lineWidth, mouseX, mouseY,this.lineStyle);
this.selected.setAttribute('id', 'connector:' + createUUID());
this.addNewShapeListeners(this.selected);
}
Event.observe(this.container, "mousemove", this.onDrawListener);
this.renderer.setCursor(this.container,'crosshair');
}
else {
if (this.mouseDownX != snappedX || this.mouseDownY != snappedY)
this.unselect();
}
return false;
};
RichDrawEditor.prototype.isLineDrawMode=function(){
return (this.mode=='line'||this.resizeMode=='line-from'||this.resizeMode=='line-to'||this.mode=='ortho-line'
||this.mode=='curve-line')
}
/**
*if the mode is line draw then show connection points
**/
RichDrawEditor.prototype.onShapeMouseEnter=function(event){
var source=Event.element(event);
var shape=this.renderer.getShapeFromEventSource(source);
//setHelp(shape.id);
if(!this.renderer.isConnector(shape)){
var newActiveShape=shape;
if((this.lineActiveShape&&newActiveShape&&this.lineActiveShape.id==newActiveShape.id)&&newActiveShape.id)
//revisit this
// ||(newActiveShape.id&&newActiveShape.id.indexof("shape")<0))
return;
else{
if(this.isLineDrawMode()){
this.renderer.remove($("active-shape-tracker"));
this.lineActiveShape=newActiveShape;
this.renderer.showConnectionPoints(this.lineActiveShape);
}
}
}
if(!this.isLineDrawMode()&&this.mode!='text'){
this.renderer.setCursor(this.container,"move");
}
};
/*******************MOUSE OUT***************************/
RichDrawEditor.prototype.onShapeMouseOut=function(event){
if(!this.isLineDrawMode()&&this.mode!="text")
this.renderer.setCursor(this.container,"default");
}
/**
*if the mouse leaves the container, stop listening to some events
**/
RichDrawEditor.prototype.onMouseOut=function(event){
if(event.toElement&&(event.toElement.id=='_body'||event.toElement.id=='_surround'||event.toElement.id=="palette")){
if((this.mode!='resize'&&this.mode!='select'&&this.mode!="text"))
{
var transmitData = this.copyToRemote();
if (transmitData != null)
gApplication.transmit('w', "cpy " + transmitData);
}
else if (this.selected)
{
var rect=new Object();
rect=this.renderer.bounds(this.selected);
if(!this.renderer.isConnector(this.selected))
{
//a shape
rect['x']=(rect['x']*(1.0/this.zoom)).toFixed(0);
rect['y']=(rect['y']*(1.0/this.zoom)).toFixed(0);
rect['width']=(rect['width']*(1.0/this.zoom)).toFixed(0);
rect['height']=(rect['height']*(1.0/this.zoom)).toFixed(0);
var transmitData = "mvs " + this.selected.id + " " + rect['width'] + " " + rect['height'] + " " + rect['x'] + " " + rect['y'] + " " + rect['rotation'];
}
else{
//a connector
rect['x']=(rect['x']*(1.0/this.zoom)).toFixed(0);
rect['y']=(rect['y']*(1.0/this.zoom)).toFixed(0);
rect['x2']=(rect['x2']*(1.0/this.zoom)).toFixed(0);
rect['y2']=(rect['y2']*(1.0/this.zoom)).toFixed(0);
var transmitData = "mvc " + this.selected.id + " " + rect['x'] + " " + rect['x2'] + " " + rect['y'] + " " + rect['y2'] + " " + rect['type'];
}
gApplication.transmit('w', transmitData);
}
Event.stopObserving(this.container, "mousemove", this.onDrawListener);
Event.stopObserving(this.container, "mousemove", this.onDragListener);
}
}
/**
*respond to various mouse up events
*/
RichDrawEditor.prototype.onMouseUp = function(event)
{
if (this.mode != 'select'&&this.mode!='resize'&&this.mode!='line'&&this.mode!='ortho-line')
{
setHelp("Click on the shape to select it");
}
if((this.mode!='resize'&&this.mode!='select'&&this.mode!="text"))
{
var transmitData = this.copyToRemote();
if (transmitData != null)
gApplication.transmit('w', "cpy " + transmitData);
}
else if (this.selected)
{
var rect=new Object();
rect=this.renderer.bounds(this.selected);
if(!this.renderer.isConnector(this.selected))
{
//a shape
rect['x']=(rect['x']*(1.0/this.zoom)).toFixed(0);
rect['y']=(rect['y']*(1.0/this.zoom)).toFixed(0);
rect['width']=(rect['width']*(1.0/this.zoom)).toFixed(0);
rect['height']=(rect['height']*(1.0/this.zoom)).toFixed(0);
var transmitData = "mvs " + this.selected.id + " " + rect['width'] + " " + rect['height'] + " " + rect['x'] + " " + rect['y'] + " " + rect['rotation'];
}
else{
//a connector
rect['x']=(rect['x']*(1.0/this.zoom)).toFixed(0);
rect['y']=(rect['y']*(1.0/this.zoom)).toFixed(0);
rect['x2']=(rect['x2']*(1.0/this.zoom)).toFixed(0);
rect['y2']=(rect['y2']*(1.0/this.zoom)).toFixed(0);
var transmitData = "mvc " + this.selected.id + " " + rect['x'] + " " + rect['x2'] + " " + rect['y'] + " " + rect['y2'] + " " + rect['type'];
}
gApplication.transmit('w', transmitData);
}
Event.stopObserving(this.container, "mousemove", this.onDrawListener);
Event.stopObserving(this.container, "mousemove", this.onDragListener);
if(this.dragStarted)
{
this.clearShapeText();
this.resetShapeText();
this.dragStarted=false;
}
if(this.mode=='line'||this.mode=='curve-line'||this.resizeMode=='line-from'||this.resizeMode=='line-to'||this.mode=='ortho-line')
{
//todo add show marker logic here
if(this.resizeMode=='line-from')
this.renderer.connectLine(this.lineActiveShape,this.selected,"from");
else if(this.resizeMode=='line-to'||this.mode=='line'||this.mode=='ortho-line'||this.mode=='curve-line')
this.renderer.connectLine(this.lineActiveShape,this.selected,"to");
this.renderer.remove($('active-shape-tracker'));
this.lineActiveShape=null;
this.clearShapeText();
this.resetShapeText();
}
if(this.mode=="text"&&this.textToolBeginNew){
this.beginTextToolEdit(this.selected);
this.textToolBeginNew=false;
}
else if(this.mode=="text"&&!this.textToolBeginNew){
setHelp("<font color='red'>Text Mode:</font>Click again to draw another text shape");
var transmitData = this.copyToRemote();
if (transmitData != null)
gApplication.transmit('w', "cpy " + transmitData);
}
if(this.mode=='resize'){
Event.stopObserving(this.container, "mousemove", this.onDrawListener);
this.clearShapeText();
this.resetShapeText();
this.setMode(this.prevMode);
this.resizeMode="";
}
if (this.mode != 'select'&&this.mode!='line'&&this.mode!='ortho-line'&&this.mode!="text"&&this.mode!='curve-line') {
this.setMode('select');
}
else{
//mainly to refresh the cursor!!!
this.setMode(this.mode);
}
};
/**
*begin text tool edit will first set the stroke-width to 0 and then start text editing
*@param {shape} selected shape
**/
RichDrawEditor.prototype.beginTextToolEdit=function(shape){
this.renderer.setStrokeWidth(shape,"0px");
this.renderer.setOpacity(shape,"0.0");
this.startTextEdit(shape);
}
/*****************ON DRAG**********************/
/**
*move the shape
**/
RichDrawEditor.prototype.onDrag = function(event) {
var offset = Position.cumulativeOffset(this.container);
var snappedX = Math.round((Event.pointerX(event) - offset[0]) / this.gridX) * this.gridX;
var snappedY = Math.round((Event.pointerY(event) - offset[1]) / this.gridY) * this.gridY;
var deltaX = snappedX - this.mouseDownX;
var deltaY = snappedY - this.mouseDownY;
if(!this.dragStarted==true){
this.clearShapeText();
this.dragStarted=true;
}
if(this.renderer.isConnector(this.selected)){
this.renderer.disconnectLineFromShape(this.selected,"to");
this.renderer.disconnectLineFromShape(this.selected,"from");
this.renderer.moveCompleteLine(this.selected,this.selectedBounds,deltaX,deltaY);
this.clearShapeText();
}
else{
this.renderer.move(this.selected, (this.selectedBounds.x*1) + deltaX, (this.selectedBounds.y*1) + deltaY);
this.renderer.moveLineWithShape(this.selected);
}
// Update selection tracker
this.renderer.updateTracker(this.selected);
this.updateShapeInfo(this.selected);
};
/**
*move 1px at a time--reacting to arrow key press
**/
RichDrawEditor.prototype.fineMove=function(left,right,up,down){
if(this.selected){
if(this.renderer.isConnector(this.selected)) return;
var deltaX=right-left;
var deltaY=down-up;
//this.selectedBounds = this.renderer.bounds(this.selected);
if(deltaY==0){
this.renderer.fineMove(this.selected, deltaX, true);
}
else{
this.renderer.fineMove(this.selected, deltaY, false);
}
this.renderer.moveLineWithShape(this.selected);
this.renderer.updateTracker(this.selected);
//this.updateShapeInfo(this.selected);
this.selectedBounds = this.renderer.bounds(this.selected);
}
else{
setHelp("Select a shape for Fine move");
}
}
/**************ON DRAW*****************/
/**
*either create new or resize existing
**/
RichDrawEditor.prototype.onDraw = function(event) {
if (this.selected == null)
return;
var offset = Position.cumulativeOffset(this.container);
var snappedX = Math.round((Event.pointerX(event) - offset[0]) / this.gridX) * this.gridX;
var snappedY = Math.round((Event.pointerY(event) - offset[1]) / this.gridY) * this.gridY;
//this means we are drawing a new shape or line on the canvas
if(this.mode!='resize'&&this.mode!='select'){
var mouseX=(this.mouseDownX*1)+this.container.parentNode.scrollLeft;
var mouseY=( this.mouseDownY*1)+this.container.parentNode.scrollTop;
var sx=(snappedX*1)+this.container.parentNode.scrollLeft;
var sy=(snappedY*1)+this.container.parentNode.scrollTop;
this.renderer.resize(this.selected, mouseX,mouseY,sx,sy);
this.updateShapeInfo(this.selected);
//we show tracker during draw only for connectors
if(this.renderer.isConnector(this.selected)){
this.renderer.updateTracker(this.selected);
}
return;
}
//otherwise check the resize mode, if the mode is horizontal then keep left static
//otherwise if mode is vertical keep the top static
if(this.mode=='resize'||this.mode=='select'){
this.resizeCounter++;
if(this.resizeCounter!=2){
return;
}
this.resizeCounter=0;
if(this.resizeMode=="line-from"){
var sx=(snappedX*1)+this.container.parentNode.scrollLeft;
var sy=(snappedY*1)+this.container.parentNode.scrollTop;
this.renderer.disconnectLineFromShape(this.selected,"from");
this.renderer.moveLine(this.selected,sx,sy,true);
}
else if(this.resizeMode=="line-to"){
var sx=(snappedX*1)+this.container.parentNode.scrollLeft;
var sy=(snappedY*1)+this.container.parentNode.scrollTop;
this.renderer.disconnectLineFromShape(this.selected,"to");
this.renderer.moveLine(this.selected,sx,sy,false);
}
//add control point listeners
else if(this.resizeMode=="control1"){
var sx=(snappedX*1)+this.container.parentNode.scrollLeft;
var sy=(snappedY*1)+this.container.parentNode.scrollTop;
this.renderer.setControl1(this.selected,sx,sy);
}
else if(this.resizeMode=="control2"){
var sx=(snappedX*1)+this.container.parentNode.scrollLeft;
var sy=(snappedY*1)+this.container.parentNode.scrollTop;
this.renderer.setControl2(this.selected,sx,sy);
}
//use this for right pull
if(this.resizeMode=="right-stretch"){
this.renderer.resizeWidth(this.selected, snappedX,snappedY, this.mouseDownX,this.mouseDownY,this.prevWidth,true);
this.renderer.moveLineWithShape(this.selected);
}
else
if(this.resizeMode=="left-stretch"){
this.renderer.resizeWidth(this.selected, snappedX,snappedY, this.mouseDownX,this.mouseDownY,this.prevWidth,false);
this.renderer.moveLineWithShape(this.selected);
}
//use this for bottom pull
else if(this.resizeMode=="bottom-stretch"){
this.renderer.resizeHeight(this.selected, snappedX,snappedY, this.mouseDownX,this.mouseDownY,this.prevHeight,true);
this.renderer.moveLineWithShape(this.selected);
}
else if(this.resizeMode=="top-stretch"){
this.renderer.resizeHeight(this.selected, snappedX,snappedY, this.mouseDownX,this.mouseDownY,this.prevHeight,false);
this.renderer.moveLineWithShape(this.selected);
}
else if(this.resizeMode=="rotate"){
var mouseX=(this.mouseDownX*1)+this.container.parentNode.scrollLeft;
var mouseY=( this.mouseDownY*1)+this.container.parentNode.scrollTop;
var sx=(snappedX*1)+this.container.parentNode.scrollLeft;
var sy=(snappedY*1)+this.container.parentNode.scrollTop;
this.processRotate(this.selected, sx,sy,mouseX,mouseY);
this.renderer.moveLineWithShape(this.selected);
}
this.renderer.updateTracker(this.selected);
this.updateShapeInfo(this.selected);
}
return false;
};
/*******************ROTATION FUNCTIONS**********************/
/**
*rotate 1 degree at a time
**/
RichDrawEditor.prototype.fineRotateSelection=function(angle){
if(this.selected==null){
setHelp("Please select a shape to rotate");
return false;
}
//this.selectedBounds = this.renderer.bounds(this.selected);
this.renderer.fineRotateSelection(this.selected,angle);
this.renderer.moveLineWithShape(this.selected);
this.renderer.updateTracker(this.selected);
this.selectedBounds = this.renderer.bounds(this.selected);
}
/**
* this method obtains the actual number of degrees to rotate by, renderer performs the actual rotation
*@param snappedX (currentX)
*@param snappedY (currentY)
*@param mouseDownX
*@param mouseDownY
**/
RichDrawEditor.prototype.processRotate=function(shape,snappedX,snappedY,mouseDownX,mouseDownY){
var rect=this.renderer.bounds(shape);
var centerX=(rect['x']*1)+(rect['width']/2);
var centerY=(rect['y']*1)+(rect['height']/2);
//first translate snapped x and y to origin
var transX=snappedX-centerX;
var transY=snappedY-centerY;
//now we are at origin, our arbitrary point would be 0,-10
//now take the dot product
var adotb=(transX*0)+(transY*(-10));
//now cros product |A|*|B|=sqrt((x1square+y1square))*sqrt((x2square+y2square));
//we know sqrt((x1square+y1square))=10
var acrossb=(10)*Math.sqrt((transX*transX)+(transY*transY));
var theta=adotb/acrossb;
theta=Math.acos(theta);
theta=rad2Deg(theta)
//if in quadrant 3 or 4
if(transX<=0)theta=360-theta;
this.renderer.rotate(this.selected,Math.round(theta));
}
/******************* END ROTATION FUNCTIONS**********************/
/**
*basically when a shape is has a mouse hit...select it. If we are in text edit mode,
*do nothing, just return;
*@param the event
**/
RichDrawEditor.prototype.onHit = function(event) {
if(this.textEditMode){
return;
}
if (this.mode == 'select') {
this.unselect();
var source=Event.element(event);
this.select(this.renderer.getShapeFromEventSource(source));
this.selectedBounds = this.renderer.bounds(this.selected);
var offset = Position.cumulativeOffset(this.container);
this.mouseDownX = Math.round((Event.pointerX(event) - offset[0]) / this.gridX) * this.gridX;
this.mouseDownY = Math.round((Event.pointerY(event) - offset[1]) / this.gridY) * this.gridY;
Event.observe(this.container, "mousemove", this.onDragListener);
}
};
/**
* update the properties box with shape or page info
* @param the shape
**/
RichDrawEditor.prototype.updateShapeInfo=function(selected){
var rect=new Object();
if(selected==null){
//show page properties
rect['width'] = this.width;
rect['height'] = this.height;
this.pageProps.width.value=rect['width'];
this.pageProps.height.value=rect['height'];
this.shapeProps.table.style.visibility="hidden";
this.shapeProps.table.style.display="none";
this.pageProps.table.style.visibility="visible";
this.pageProps.table.style.display="";
this.lineProps.table.style.visibility="hidden";
this.lineProps.table.style.display="none";
}
else{
rect=this.renderer.bounds(selected);
//this is a shape
if(!this.renderer.isConnector(selected)){
rect['x']=(rect['x']*(1.0/this.zoom)).toFixed(0);
rect['y']=(rect['y']*(1.0/this.zoom)).toFixed(0);
rect['width']=(rect['width']*(1.0/this.zoom)).toFixed(0);
rect['height']=(rect['height']*(1.0/this.zoom)).toFixed(0);
this.shapeProps.width.value=rect['width'];
this.shapeProps.height.value=rect['height'];
this.shapeProps.x.value=rect['x'];
this.shapeProps.y.value=rect['y'];
this.shapeProps.rotation.value=rect['rotation'];
this.shapeProps.table.style.visibility="visible";
this.shapeProps.table.style.display="";
this.lineProps.table.style.visibility="hidden";
this.lineProps.table.style.display="none";
this.pageProps.table.style.visibility="hidden";
this.pageProps.table.style.display="none";
}
else{
//its a connector
rect['x']=(rect['x']*(1.0/this.zoom)).toFixed(0);
rect['y']=(rect['y']*(1.0/this.zoom)).toFixed(0);
rect['x2']=(rect['x2']*(1.0/this.zoom)).toFixed(0);
rect['y2']=(rect['y2']*(1.0/this.zoom)).toFixed(0);
this.lineProps.x1.innerHTML=rect['x'];
this.lineProps.x2.innerHTML=rect['x2'];
this.lineProps.y1.innerHTML=rect['y'];
this.lineProps.y2.innerHTML=rect['y2'];
this.lineProps.type.innerHTML=rect['type'];
this.shapeProps.table.style.visibility="hidden";
this.shapeProps.table.style.display="none";
this.lineProps.table.style.visibility="visible";
this.lineProps.table.style.display="";
this.pageProps.table.style.visibility="hidden";
this.pageProps.table.style.display="none";
}
}
};
/**
* append a cumulate draw specific page attribute to the save data
**/
RichDrawEditor.prototype.appendPageAttribute=function(div,attribute){
this.renderer.appendPageAttribute(div,attribute);
}
/**
*get the vml/svg data embedded in the richdraw editor
**/
RichDrawEditor.prototype.getRealData=function(){
return this.renderer.getRealData();
}
/**
*take the response text and return valid data from it
**/
RichDrawEditor.prototype.getValidDocumentFromResponse=function(response){
return this.renderer.getValidDocumentFromResponse(response);
}
/**
*load palette, does this really belong in the editor?
**/
RichDrawEditor.prototype.loadPalette=function(id){
var object=this.renderer.loadXML("shapes/palettes/"+id+".xml");
return object.getElementsByTagName("palette")[0];
}
/**
*method to update the shape properties, take zoom factor into account here and also
*move any connectors attached to the shape
**/
RichDrawEditor.prototype.updateShape=function(width,height,x,y,rotation){
if(this.selected){
var rect=this.selected;
width=(width*(this.zoom/1.0)).toFixed(0);
height=(height*(this.zoom/1.0)).toFixed(0);
x=(x*(this.zoom/1.0)).toFixed(0);
y=(y*(this.zoom/1.0)).toFixed(0);
this.renderer.setWidth(this.selected,width);
this.renderer.setHeight(this.selected,height);
this.renderer.setX(this.selected,x);
this.renderer.setY(this.selected,y);
this.renderer.setRotation(this.selected,rotation);
this.renderer.updateTracker(this.selected);
this.renderer.moveLineWithShape(this.selected);
this.clearShapeText(this.selected);
this.resetShapeText(this.selected);
} else{
setHelp("Please select a shape to update");
}
}
/**
*utility function to convert rad to degrees
**/
function rad2Deg(angle){
return angle * (180 / Math.PI);
}
/**
*create a unique id for shapes
**/
function createUUID()
{
return [4, 2, 2, 2, 6].map(function(length) {
var uuidpart = "";
for (var i=0; i<length; i++) {
var uuidchar = parseInt((Math.random() * 256)).toString(16);
if (uuidchar.length == 1)
uuidchar = "0" + uuidchar;
uuidpart += uuidchar;
}
return uuidpart;
}).join('-');
}
function show(object){document.getElementById(object).style.visibility='visible';document.getElementById(object).style.display='';}
function hide(object){document.getElementById(object).style.visibility='hidden';document.getElementById(object).style.display='none';}
RichDrawEditor.prototype.setUser=function(aUser){
this.iUser=aUser;
}
RichDrawEditor.prototype.handleRemoteCommand=function(param)
{
var name = param.substr(0,param.indexOf(" "));
var remoteData = param.substr(param.indexOf(" ")+1);
var command = remoteData.substring(0,3);
var content = remoteData.substring(4);
if (command=="ann")
{
//announce start of a drawing
insertInvitation(name);
}
else if (command=="stp")
{
//announce end of a drawing
removeInvitation(name);
gApplication.removePeer(name);
}
else if (command=="con")
{
//connect from user
gApplication.sendPeerList(name);
sendCurrentState(name);
gApplication.addPeer(name);
}
else if (command=="aus")
{
//add user
gApplication.addPeer(content);
}
else if (command=="rus")
{
//add user
gApplication.removePeer(name);
}
else if (command=="loa")
{
loadData(content);
}
else if (command=="cpy")
{
var node=this.renderer.paste(content,true);
//add listener to added child
this.addNewShapeListeners(node);
this.clipboard=this.renderer.copy(node);
return node;
}
else if (command=="cmd")
{
var temp = content.split(" ");
var oldID = null;
if (this.selected)
oldID=this.selected.id
if (temp[2])
this.selected = $(temp[2])
if (temp[0]=="zoom")
{
this.externaleditCommand(temp[0], temp[1], true);
$('_zoomValue').innerHTML=(c.getZoom()*100).toFixed(0)+"%";
}
else if (temp[0]=="fontFamily")
{
if (temp.length==5)
{
this.selected = $(temp[4])
this.externaleditCommand(temp[0], temp[1] + " " + temp[2] + " " + temp[3], true);
}
else if (temp.length==4)
{
this.selected = $(temp[3])
this.externaleditCommand(temp[0], temp[1] + " " + temp[2], true);
}
else
this.externaleditCommand(temp[0], temp[1], true);
}
else if (temp[0]=="fillcolor")
{
this.externaleditCommand(temp[0], temp[1], true);
}
else if (temp[0]=="linecolor")
{
this.externaleditCommand(temp[0], temp[1], true);
}
else if (temp[0]=="linewidth")
{
this.externaleditCommand(temp[0], temp[1], true);
}
else if (temp[0]=="linedashstyle")
{
this.externaleditCommand(temp[0], temp[1], true);
}
else if (temp[0]=="opacity")
{
this.externaleditCommand(temp[0], temp[1], true);
}
else if (temp[0]=="shadow")
{
this.externaleditCommand(temp[0], temp[1], true);
}
else if (temp[0]=="gradient")
{
this.externaleditCommand(temp[0], temp[1], true);
}
else if (temp[0]=="fontSize")
{
this.externaleditCommand(temp[0], temp[1], true);
}
else if (temp[0]=="fontColor")
{
this.externaleditCommand(temp[0], temp[1], true);
}
else if (temp[0]=="bold")
{
this.externaleditCommand(temp[0], temp[1], true);
}
else if (temp[0]=="italic")
{
this.externaleditCommand(temp[0], temp[1], true);
}
else if (temp[0]=="align")
{
this.externaleditCommand(temp[0], temp[1], true);
}
else if (temp[0]=="bringtofront")
{
this.bringToFront();
}
else if (temp[0]=="sendtoback")
{
this.sendToBack();
}
else if (temp[0]=="reset")
{
this.removeAll();
this.setPageSize(this.DEFAULT_PAGE_WIDTH,this.DEFAULT_PAGE_HEIGHT);
}
else if (temp[0]=="deleteSelection")
{
this.deleteSelection();
}
else if (temp[0]=="txt")
{
var newtext = remoteData.substring(9+temp[1].length+temp[2].length);
var shapeFont=this.renderer.getFont(this.selected);
this.renderer.setShapeText(this.selected,newtext,this.font,false,shapeFont,this.zoom);
}
else if (temp[0]=="grid")
{
if(temp[0]=='on')
{
$('_page').style.backgroundImage="url(images/grid.jpg)";
}
else{
$('_page').style.backgroundImage="";
}
}
if (oldID)
this.select($(oldID));
}
if (command=="mvs")
{
var oldID = null;
if (this.selected)
oldID=this.selected.id
//moving a shape
var temp = content.split(" ");
this.selected = $(temp[0]);
if (this.selected)
this.updateShape(temp[1], temp[2], temp[3], temp[4], temp[5]);
if (oldID)
this.select($(oldID));
}
else if (command=="mvc")
{
//moving a connector
}
else if (command=="pgs")
{
//set page size
var temp = content.split(" ");
this.setPageSize(temp[0],temp[1]);
}
}
function transmit(aUser, aApplication, aMessage)
{
//loop through all users and transmit to them
if (typeof(window.external)!="undefined" && typeof(window.external.transmit)!="undefined")
window.external.transmit(aUser, aApplication, aMessage);
}
//Application handling
function Application()
{
this.reset();
}
Application.prototype.reset=function()
{
this.iPeers=new Array();
this.iSource=false;
this.iViewing="";
}
Application.prototype.broadcast=function(application, message)
{
if (typeof(window.external)!="undefined" && typeof(window.external.broadcast)!="undefined")
window.external.broadcast(application, message);
}
Application.prototype.transmit=function(application, message)
{
//loop through all users and transmit to them
for (var i=0; i < this.iPeers.length; i++)
{
if (typeof(window.external)!="undefined" && typeof(window.external.transmit)!="undefined")
window.external.transmit(this.iPeers[i].iName, application, message);
}
}
Application.prototype.sendPeerList=function(aName)
{
for (var i=0; i < this.iPeers.length; i++)
{
if (typeof(window.external)!="undefined" && typeof(window.external.transmit)!="undefined")
window.external.transmit(aName, "w", "aus " + this.iPeers[i].iName);
}
}
Application.prototype.addPeer=function(aName)
{
this.iPeers[this.iPeers.length] = new Peer(aName);
insertParticipant(aName);
}
Application.prototype.checkPeerExist=function(aName)
{
for (var i = 0; i < this.iPeers.length; i++)
{
if (this.iPeers[i].iName == aName)
return true;
}
return false;
}
Application.prototype.removePeer=function(aName)
{
removeParticipant(aName);
for (var i = 0; i < this.iPeers.length; i++)
if (this.iPeers[i].iName == aName)
{
this.iPeers.splice(i,1);
return;
}
}
function Peer(aName)
{
this.iName=aName;
}
var gApplication;
//announce the drawing to the rest of the workspace.
function announce()
{
if (gApplication.iSource)
{
gApplication.broadcast('w', "ann draw");
if (iConnectionMode!="Private")
setTimeout('announce()',60000);
}
else
{
gApplication.broadcast('w', "stp draw");
}
}
function initDrawing()
{
if (!gApplication.iSource)
{
stopDrawing();
gApplication.iSource = true;
announce();
}
Activate('w');
hide("startdrawing");
show("drawparticipant");
}
function stopDrawing()
{
if (gApplication.iSource)
{
gApplication.reset();
announce();
}
else
{
this.iViewing = "";
gApplication.transmit('w', "rus ");
gApplication.reset();
var invitelist=document.getElementById("Particips");
invitelist.innerHTML="";
}
hide("drawparticipant");
Activate('c');
show("startdrawing");
}
function sendCurrentState(aName)
{
/* Try.these(c.renderer.savePolyLinePaths());
dummy=c.getRealData();
transmit(aName, 'w', "loa " + dummy);
*/
var format=c.renderer.EXTENSION;
var dummy=getAllData(format);
var data=(dummy.innerHTML)?dummy.innerHTML:dummy.xml;
transmit(aName, 'w', "loa " + data);
}
function loadData(content)
{
if(content){
var div=c.getValidDocumentFromResponse(content)
c.open(div);
}
}
function viewDrawing(aName)
{
if (aName!=this.iViewing)
{
if (this.iViewing)
{
//we are viewing somebody, disconnect from them before connecting
}
this.iViewing=aName;
if (!gApplication.checkPeerExist(aName))
{
gApplication.addPeer(aName);
gApplication.iSource=false;
gApplication.transmit('w', "con " + aName);
}
hide("startdrawing");
show("drawparticipant");
}
Activate("w");
}
function insertInvitation(aUser, aMessage)
{
var invitelist = document.getElementById("Invites");
var existingItem = document.getElementById('invite' + aUser);
if (!existingItem)
{
var listElement = document.createElement("li");
listElement.setAttribute('id', 'invite' + aUser);
var newlink = document.createElement('a');
newlink.setAttribute('href', 'javascript:viewDrawing("' + aUser + '")');
var text = document.createTextNode(aUser);
newlink.appendChild(text);
listElement.appendChild(newlink);
invitelist.appendChild(listElement);
if (typeof(window.external)!="undefined" && typeof(window.external.observe)!="undefined")
window.external.observe(aUser);
var chatElement = document.createElement("div");
var newlink = document.createElement('a');
newlink.setAttribute('href', 'javascript:viewDrawing("' + aUser + '")');
var text = document.createTextNode("Click here");
newlink.appendChild(text);
var text2 = document.createTextNode(aUser + " started a shared whiteboard. ");
var text3 = document.createTextNode(" to view or take part in the drawing. ");
chatElement.appendChild(text2);
chatElement.appendChild(newlink);
chatElement.appendChild(text3);
var chat = document.getElementById("c");
chat.appendChild(chatElement);
}
}
function removeInvitation(aUser)
{
var invitelist = document.getElementById("Invites");
var removeItem = document.getElementById('invite' + aUser);
if (removeItem)
{
invitelist.removeChild(removeItem);
if (typeof(window.external)!="undefined" && typeof(window.external.ignore)!="undefined")
window.external.ignore(aUser);
}
}
function insertParticipant(aUser, aMessage)
{
var invitelist = document.getElementById("Particips");
var existingItem = document.getElementById('participant' + aUser);
if(!existingItem)
{
var listElement = document.createElement("li");
listElement.setAttribute('id', 'participant' + aUser);
var text = document.createTextNode(aUser);
listElement.appendChild(text);
invitelist.appendChild(listElement);
if (typeof(window.external)!="undefined" && typeof(window.external.observe)!="undefined")
window.external.observe(aUser);
}
}
function removeParticipant(aUser)
{
var invitelist = document.getElementById("Particips");
var removeItem = document.getElementById('participant' + aUser);
if (removeItem)
{
invitelist.removeChild(removeItem);
if (typeof(window.external)!="undefined" && typeof(window.external.ignore)!="undefined")
window.external.ignore(aUser);
}
}
function userLeft(aUser)
{
gApplication.removePeer(aUser);
removeInvitation(aUser);
}